package com.ruoyi.modules.system.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysJob;
import com.ruoyi.common.cron.CronJob;
import com.ruoyi.common.cron.CronJobInterface;
import com.ruoyi.common.utils.AssertUtils;
import com.ruoyi.common.utils.CronUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.modules.system.enums.SysJobStatus;
import com.ruoyi.modules.system.mapper.SysJobMapper;
import com.ruoyi.modules.system.service.ISysJobService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 定时任务Service业务层处理
 *
 * @author ruoyi
 * @date 2025-06-04
 */
@Service
public class SysJobServiceImpl implements ISysJobService, CronJobInterface {

    @Resource
    private SysJobMapper baseMapper;

    @Override
    public List<CronJob> loadCronJobs() {
        List<SysJob> sysJobs = baseMapper.selectList(
            Wrappers.lambdaQuery(SysJob.class).eq(SysJob::getStatus, SysJobStatus.RUNNING.getCode()));
        return CollStreamUtil.toList(sysJobs, SysJob::toCronJob);
    }

    /**
     * 查询定时任务
     */
    @Override
    public SysJob queryById(Long jobId) {
        return baseMapper.selectVoById(jobId);
    }

    /**
     * 查询定时任务列表
     */
    @Override
    public Page<SysJob> queryPageList(SysJob bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysJob> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoPage(pageQuery.build(), lqw);
    }

    /**
     * 查询定时任务列表
     */
    @Override
    public List<SysJob> queryList(SysJob bo) {
        LambdaQueryWrapper<SysJob> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysJob> buildQueryWrapper(SysJob bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysJob> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getJobName()), SysJob::getJobName, bo.getJobName());
        lqw.like(StringUtils.isNotBlank(bo.getJobGroup()), SysJob::getJobGroup, bo.getJobGroup());
        lqw.eq(bo.getStatus() != null, SysJob::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增定时任务
     */
    @Override
    public Boolean insertByBo(SysJob sysJob) {
        // 保存前的数据校验
        validEntityBeforeSave(sysJob);
        sysJob.setStatus(SysJobStatus.STOPPED.getCode());
        boolean flag = baseMapper.insert(sysJob) > 0;
        if (flag) {
            sysJob.setJobId(sysJob.getJobId());
        }
        return flag;
    }

    /**
     * 修改定时任务
     */
    @Override
    public Boolean updateByBo(SysJob sysJob) {
        // 保存前的数据校验
        validEntityBeforeSave(sysJob);
        boolean flag = baseMapper.updateById(sysJob) > 0;
        if (flag) {
            CronUtils.removeJob(sysJob.getJobId());
            if (SysJobStatus.RUNNING.getCode().equals(sysJob.getStatus())) {
                CronUtils.addJob(sysJob.toCronJob());
            }
        }
        return flag;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysJob entity) {
        // Cron表达式错误
        AssertUtils.isTrue(CronUtils.isValid(entity.getCronExpression()), "Cron表达式错误");
    }

    /**
     * 批量删除定时任务
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid && ObjectUtil.isNotEmpty(ids)) {
            // 存在运行中状态需要先停止
            Long count = baseMapper.selectCount(
                Wrappers.lambdaQuery(SysJob.class).in(SysJob::getJobId, ids).eq(SysJob::getStatus, SysJobStatus.RUNNING.getCode()));
            AssertUtils.isTrue(count > 0, "定时任务运行中,请先停止运行");
        }
        boolean flag = baseMapper.deleteBatchIds(ids) > 0;
        if (flag) {
            ids.forEach(CronUtils::removeJob);
        }
        return flag;
    }

    @Override
    public Boolean updateStatus(SysJob bo) {
        SysJob sysJob = baseMapper.selectById(bo.getJobId());
        AssertUtils.notNull(sysJob, "任务不存在");
        // 未修改状态直接返回
        if (Objects.equals(sysJob.getStatus(), bo.getStatus())) {
            return true;
        }
        sysJob.setStatus(bo.getStatus());
        return updateByBo(sysJob);
    }
}
